package de.koller.aframe.util.filter;

import de.koller.aframe.util.math.FunctionPreview;
import de.koller.aframe.util.math.IFunction;
import de.koller.aframe.util.math.interpolation.CubicInterpolation;
import de.koller.oceanFramework.gl.util.RasterManager;
import de.koller.oceanFramework.util.ColorIntUtil;

public class Convolution {
	public static boolean SHOW_PROGRESS = false;
	
	public static void lin( RasterManager texture, RasterManager out, IFunction conv, int convSize ) {
		RasterManager tmp = new RasterManager( out.getWidth(), out.getHeight() );
		FilterMatrixLin filterLin = new FilterMatrixLin( convSize, conv );
		filterLin.use( texture, tmp, true );
		filterLin.use( tmp, out, false );
	}
	
	public static IFunction cubicFilter( final int size ) {
		return new IFunction() {
			@Override public float getValue( float x ) {
				x = 1f / size * x;
				if( x < 0 ) return 1;
				if( x > 1 ) return 0;
				return CubicInterpolation.cubic( x, 0, 1, 0, 1 );
			}
		};
	}
	
	public static void main( String[] args ) {
		FunctionPreview.showFunction( -1, 11, Convolution.cubicFilter( 10 ) );
	}
	
	private static class FilterMatrixLin {
		private final float[] matrix;
	
		private FilterMatrixLin( int matrixSize, IFunction matrixFill ) {
			matrix = new float[ matrixSize ];
			fillMatrix( matrixFill );
		}
		
		private void fillMatrix( IFunction matrixFill ) {
			float s = 0;
			int cx = matrix.length / 2;
			for( int x = 0; x < matrix.length; x++ ) {
				float k = (float)Math.abs( cx - x );
				double f = matrixFill.getValue( k );
				matrix[x] = (float)f;
				s += matrix[x];
			}
			
			for( int x = 0; x < matrix.length; x++ )
				matrix[x] /= s;
		}
		
		public void use( RasterManager t, RasterManager out, boolean vertical ) {
			RasterManager m = out;
			System.arraycopy( t.getData(), 0, m.getData(), 0, t.getData().length );
			
			for( int x = 0; x < t.getWidth(); x++ ) {
				for( int y = 0; y < t.getHeight(); y++ )
					convAt( t, m, x, y, vertical );
				
				if( SHOW_PROGRESS )
					if( x % 100 == 0 )
						System.out.println( x + " step " + (vertical?"1":"2") );
			}
			
			//System.arraycopy( m.getData(), 0, t.getData(), 0, t.getData().length );
		}
		
		private void convAt( RasterManager org, RasterManager out, int x, int y, boolean vertical ) {
			float a = 0;
			float r = 0;
			float g = 0;
			float b = 0;
			for( int mx = 0; mx < matrix.length; mx++ ) {
				int mc = 0;
				
				if( !vertical )
					mc = colorAt( org,	x - (matrix.length/2) + mx, y );
				else
					mc = colorAt( org,	x, y - (matrix.length/2) + mx );
				
				float m = matrix[mx];

				a += ColorIntUtil.getAValue( mc ) * m;
				r += ColorIntUtil.getRValue( mc ) * m;
				g += ColorIntUtil.getGValue( mc ) * m;
				b += ColorIntUtil.getBValue( mc ) * m;
			}
			
			out.setPixel( ColorIntUtil.getIntColor( (int)a, (int)r, (int)g, (int)b ), x, y );
		}
			
	}
	
	private static int colorAt( RasterManager m, int x, int y ) {
		int sx = x;
		int sy = y;
		if( sx < 0 ) sx = 0;
		if( sy < 0 ) sy = 0;
		if( sx >= m.getWidth() ) sx = m.getWidth() - 1;
		if( sy >= m.getHeight() ) sy = m.getHeight() - 1;

		return m.colorAt( sx, sy );
	}
	
}
